// FeatureProcessor.js

export class FeatureProcessor {
  constructor() {
    this.features = null;
    this.subscribers = [];
    this.audio = null;
    this.isPlaying = false;
  }

  // Load features data from JSON file
  async loadFeatures() {
    try {
      const response = await fetch('./data/gthljxq.feature.json');
      const data = await response.json();
      this.features = data;
      console.log('Feature data loaded successfully');
    } catch (error) {
      console.error('Failed to load features data:', error);
      throw error;
    }
  }

  // Initialize audio playback
  initAudio() {
    this.audio = new Audio('./data/gthljxq.mp3');
    this.audio.addEventListener('play', () => {
      this.isPlaying = true;
      this.update();
      console.log('Audio playback started');
    });
    
    this.audio.addEventListener('pause', () => {
      this.isPlaying = false;
      console.log('Audio playback paused');
    });
    
    this.audio.addEventListener('ended', () => {
      this.isPlaying = false;
      console.log('Audio playback ended');
    });
    
    console.log('Audio initialized');
  }

  // Play audio
  play() {
    if (!this.features || !this.audio) {
      console.error('Features or audio not initialized');
      return;
    }
    
    this.audio.play().catch(error => {
      console.error('Error playing audio:', error);
    });
  }

  // Pause audio
  pause() {
    if (!this.audio) {
      console.error('Audio not initialized');
      return;
    }
    
    this.audio.pause();
  }

  // Seek to a specific time
  seekTo(time) {
    if (!this.features || !this.audio) {
      console.error('Features or audio not initialized');
      return;
    }
    
    this.audio.currentTime = time;
    this.emitEvent(time);
    console.log(`Seeked to time: ${time}`);
  }

  // Get current time
  getCurrentTime() {
    if (!this.audio) return 0;
    return this.audio.currentTime;
  }

  // Get duration
  getDuration() {
    if (!this.features) return 0;
    return this.features.duration;
  }

  // Subscribe to visualization events
  subscribe(callback) {
    this.subscribers.push(callback);
    console.log('New subscriber added');
  }

  // Unsubscribe from visualization events
  unsubscribe(callback) {
    const index = this.subscribers.indexOf(callback);
    if (index > -1) {
      this.subscribers.splice(index, 1);
      console.log('Subscriber removed');
    }
  }

  // Update loop
  update() {
    if (!this.isPlaying || !this.features || !this.audio) return;

    const currentTime = this.audio.currentTime;
    this.emitEvent(currentTime);

    if (this.isPlaying) {
      requestAnimationFrame(this.update.bind(this));
    }
  }

  // Emit visualization event to all subscribers
  emitEvent(currentTime) {
    if (!this.features) return;
    
    const frameIndex = Math.floor(currentTime * this.features.fps);
    
    // Make sure we don't go out of bounds
    if (frameIndex >= this.features.frames || frameIndex < 0) {
      return;
    }

    const event = {
      time: currentTime,
      spectralCentroid: this.features.features.spectral_centroids[frameIndex] || 0,
      spectralRolloff: this.features.features.spectral_rolloff[frameIndex] || 0,
      spectralBandwidth: this.features.features.spectral_bandwidth[frameIndex] || 0,
      zeroCrossingRate: this.features.features.zero_crossing_rate[frameIndex] || 0,
      rms: this.features.features.rms[frameIndex] || 0,
      mfccs: this.features.features.mfccs.map(coefficients => coefficients[frameIndex] || 0)
    };

    // Log the event to console
    console.log('Visualization Event:', event);

    // Notify all subscribers
    this.subscribers.forEach(callback => {
      try {
        callback(event);
      } catch (error) {
        console.error('Error in visualization event subscriber:', error);
      }
    });
  }
}